home *** CD-ROM | disk | FTP | other *** search
- // Adapted from NVidia's ocean.fx example.
- // Applied to the Nile, ponds, etc.
- // Also adapted from "Effective Water Simulation from Physical Models" in GPU Gems
- string description = "Water with Environment Map, Waves and Bump Map";
-
- // Note that these matrices & the Time value must be "manually"
- // loaded by C++ game code, but are automatically set within NVidia's FX Composer.
- float4x4 worldViewProj : WorldViewProjection;
- float4x4 worldMatrix : World;
- float4x4 worldInverseTranspose : WorldInverseTranspose;
- float4x4 viewInverse : ViewInverse;
- float4x4 view : View;
-
- // Time. Used to animate waves, bump map.
- float time : Time < string UIWidget = "none"; >;
- //------------------------------------
-
- // Bump map
- texture normalMap : Normal
- <
- string ResourceName = "waves2.dds";
- string TextureType = "2D";
- >;
-
- // Cube map
- texture cubeMap : Environment
- <
- string ResourceName = "CloudyHillsCubemap2.dds";
- string TextureType = "Cube";
- >;
-
- // Texture sampling attributes
- sampler2D normalMapSampler = sampler_state
- {
- Texture = <normalMap>;
- #if 0
- // this is a trick from Halo - use point sampling for sparkles
- MagFilter = Linear;
- MinFilter = Point;
- MipFilter = None;
- #else
- MagFilter = Linear;
- MinFilter = Linear;
- MipFilter = Linear;
- AddressU = Wrap; // very important, otherwise the bump map disappears at certain orientations
- AddressV = Wrap;
- #endif
- };
-
- samplerCUBE envMapSampler = sampler_state
- {
- Texture = <cubeMap>;
- MinFilter = Linear;
- MagFilter = Linear;
- MipFilter = Linear;
- };
-
- // NOTE: It may be worthwhile to set variables like bumpHeight to static const,
- // once we're done adjusting them. I think this allows increased performance, but
- // that should be double-checked. This means the values won't be visible to FX Composer.
-
- float timeMod < string UIWidget = "none"; > = 200.0;
-
- // "Height" of the bumps on the bump map
- float bumpHeight
- <
- string UIWidget = "slider";
- float UIMin = 0.0; float UIMax = 2.0; float UIStep = 0.01;
- string UIName = "Bump Height";
- > = 0.3; // was 0.1
-
- // Scale of bump map
- float2 textureScale
- <
- string UIName = "Texture scale";
- > = { 1.0, 0.5 }; // was 8.0, 4.0
-
- // How fast the bump map moves over the water. Adds to current effect.
- float2 bumpSpeed
- <
- string UIName = "Bumpmap translation speed";
- > = { 0.0, -0.05 }; // was -0.05, 0.0
-
- // Exponent for calculating Fresnel reflectance. Could probably be reduced and still look OK.
- float fresnelPower
- <
- string UIName = "Fresnel exponent";
- string UIWidget = "slider";
- float UIMin = 1.0; float UIMax = 10.0; float UIStep = 0.01;
- > = 4.0; // was 4.0
-
- // High dynamic range multiplier. Increasing this will "blow out" (brighten) the bright spots on the water
- float hdrMultiplier
- <
- string UIName = "HDR multiplier";
- string UIWidget = "slider";
- float UIMin = 0.0; float UIMax = 100.0; float UIStep = 0.01;
- > = 3.0; // was 3.0, make this 0.4?
-
- // Position of the camera in world coordinates
- float3 eyePositionW : Direction
- <
- string UIWidget = "Eye Position";
- string Space = "material";
- > = {0.0f, 1.0f, 0.0f};
-
- // Fog attribute
- float fogEnd
- <
- string UIWidget = "slider";
- float UIMin = 1.0;
- float UIMax = 128.0;
- float UIStep = 1.0;
- string UIName = "fog end";
- > = 44.0;
-
- // Calculated by C++: 1 / (FogEnd - FogStart)
- float fogEndMinusStartInv
- <
- string UIWidget = "slider";
- float UIMin = 0.01;
- float UIMax = 10.0;
- float UIStep = 0.01;
- string UIName = "fog end minus start inverse";
- > = 0.125;
-
- // Deep water color. This color will dominate when the camera is looking
- // straight down at the water (i.e. the eye vector is perpendicular to the water normal).
- float4 deepColor : Diffuse
- <
- string UIName = "Deep water color";
- > = {0.0f, 0.0f, 0.1f, 1.0f};
-
- // Shallow water color. This color will dominate when the camera is looking
- // at a grazing angle to the water (i.e. the eye vector is close to parallel to the water normal).
- float4 shallowColor : Diffuse
- <
- string UIName = "Shallow water color";
- > = {0.0, 0.5, 0.5, 1.0};
-
- // Affects the color of the env. map reflection and other reflection attributes.
- float4 reflectionColor : Specular
- <
- string UIName = "Reflection color";
- > = {1.0f, 1.0f, 1.0f, 1.0f};
-
- // these are redundant, but makes the ui easier:
- float reflectionAmount
- <
- string UIName = "Reflection amount";
- string UIWidget = "slider";
- float UIMin = 0.0; float UIMax = 2.0; float UIStep = 0.01;
- > = 1.0f; // was 1.0f
-
- // Height of the waves.
- float waveAmp
- <
- string UIName = "Wave amplitude";
- string UIWidget = "slider";
- float UIMin = 0.0; float UIMax = 10.0; float UIStep = 0.1;
- > = 0.005; // was 0.01
-
- // Frequency of the waves.
- float waveFreq
- <
- string UIName = "Wave frequency";
- string UIWidget = "slider";
- float UIMin = 0.0; float UIMax = 1.0; float UIStep = 0.001;
- > = 1.0; //was 0.1
- // wave functions
-
- // Wave structure
- struct WAVE {
- float freq; // 2*PI / wavelength
- float amp; // amplitude
- float phase; // speed * 2*PI / wavelength
- float2 dir; // direction
- };
-
- // We'll mix a couple of waves with different heights, frequencies, etc.
- #define NWAVES 2
- WAVE wave[NWAVES] = {
- { 1.0, 1.0, 0.5, float2(1, 0) },
- { 2.0, 0.5, 1.3, float2(0.7, -0.7) }
- };
-
- // Determine the height of the wave at a given location and time
- float evaluateWave(WAVE w, float2 pos, float t)
- {
- return w.amp * sin( dot(w.dir, pos)*w.freq + t*w.phase);
- }
- // derivative of wave function
- float evaluateWaveDeriv(WAVE w, float2 pos, float t)
- {
- return w.freq*w.amp * cos( dot(w.dir, pos)*w.freq + t*w.phase);
- }
-
- // sharp wave functions. Makes waves with sharper peaks.
- float evaluateWaveSharp(WAVE w, float2 pos, float t, float k)
- {
- return w.amp * pow(sin( dot(w.dir, pos)*w.freq + t*w.phase)* 0.5 + 0.5 , k);
- }
-
- float evaluateWaveDerivSharp(WAVE w, float2 pos, float t, float k)
- {
- return k*w.freq*w.amp * pow(sin( dot(w.dir, pos)*w.freq + t*w.phase)* 0.5 + 0.5 , k - 1) * cos( dot(w.dir, pos)*w.freq + t*w.phase);
- }
-
- //------------------------------------
- // Passed in to vertex shader
- struct vertexInput {
- float3 position : POSITION;
- float3 normal : NORMAL;
- float4 color : COLOR;
- float2 texCoord : TEXCOORD0;
- };
-
- // Vertex shader output, passed in to pixel shader
- struct vertexOutput2 {
- float4 Position : POSITION; // in clip space
- float4 color0 : COLOR0;
- float4 color1 : COLOR1;
- float4 TexCoord : TEXCOORD0;
- float4 btn_x : TEXCOORD1; // binormal.x, tangent.x, normal.x
- float4 btn_y : TEXCOORD2; // binormal.y, tangent.y, normal.y
- float4 btn_z : TEXCOORD3; // binormal.z, tangent.z, normal.z
- float fog : FOG;
- };
-
- // Vertex shader output, passed in to pixel shader
- struct vertexOutput3 {
- float4 Position : POSITION; // in clip space
- float2 TexCoord : TEXCOORD0;
- float3 TexCoord1 : TEXCOORD1; // first row of the 3x3 transform from tangent to cube space
- float3 TexCoord2 : TEXCOORD2; // second row of the 3x3 transform from tangent to cube space
- float3 TexCoord3 : TEXCOORD3; // third row of the 3x3 transform from tangent to cube space
-
- float2 bumpCoord0 : TEXCOORD4;
- float2 bumpCoord1 : TEXCOORD5;
- float2 bumpCoord2 : TEXCOORD6;
-
- float3 eyeVector : TEXCOORD7;
- float fog : FOG;
- };
-
- //------------------------------------
-
- // Vertex shader which computes waves, tangent basis to waves, bump map texture coordinates.
- vertexOutput2 VS_Transform2(vertexInput IN,
- uniform float time,
- uniform float waveFreq,
- uniform float waveAmp,
- uniform WAVE theWaves[NWAVES],
- uniform float4x4 theWorldViewProj,
- uniform float4x4 theView,
- uniform float2 textureScale,
- uniform float2 bumpSpeed,
- uniform float BumpScale,
- uniform float3 theEyePosition,
- uniform float theFogEnd,
- uniform float theFogEndMinusStartInv
- )
- {
- vertexOutput2 OUT;
-
- // We're combining two wave functions. Hard code these values
- // eventually for better performance?
- theWaves[0].freq = waveFreq;
- theWaves[0].amp = waveAmp;
-
- theWaves[1].freq = waveFreq*2.0;
- theWaves[1].amp = waveAmp*0.5;
-
- float3 P = IN.position;
-
- // Now convert world position to camera space.
- // Note that we don't use World Matrix * View Matrix here, 'cause the World Matrix is the identity matrix.
- float4 positionCamSpace = mul( float4(P, 1.0), theView );
-
- // NOTE: P is in camera space
- OUT.fog = clamp(((theFogEnd - positionCamSpace.z) * theFogEndMinusStartInv), 0.0f, 1.0f);
-
- // sum waves
- float ddx = 0.0, ddy = 0.0;
- for(int i=0; i < NWAVES; i++) {
- P.z += evaluateWave(theWaves[i], P.xy, time); //!NOTE changed this to xy from xz, due to Empire Earth code
- float deriv = evaluateWaveDeriv(theWaves[i], P.xy, time);
- ddx += deriv * theWaves[i].dir.x;
- ddy += deriv * theWaves[i].dir.y;
- }
-
- // Transform position to clip space
- OUT.Position = mul(float4(P, 1.0), theWorldViewProj);
-
- // compute tangent basis. This is used to convert object space to texture space.
- // N is the normal to the surface, T is the tangent and B is the binormal. T & B
- // follow the texture coordinate axes u and v.
- float3 B = float3(1, ddx, 0) * BumpScale;
- float3 T = float3(0, ddy, 1) * BumpScale;
- float3 N = normalize(float3(-ddx, 1, -ddy));
-
- // Now we pass in (time in seconds) fmod 200.0, so we don't have to do it for each vertex
-
- // pass texture coordinates for fetching the normal map
- OUT.TexCoord.xy = IN.texCoord*textureScale + timeMod * bumpSpeed;
- OUT.TexCoord.z = 0;
- OUT.TexCoord.w = 1;
-
- // compute the eye vector (going from shaded point to eye) in cube space
- float3 theEyeVector = (theEyePosition - P).xzy; //swap z & y (in Empire Earth code, Z points up, not Y)
- theEyeVector = normalize(theEyeVector);
-
- OUT.btn_x = float4(B.x, T.x, N.x, theEyeVector.x);
- OUT.btn_y = float4(B.y, T.y, N.y, -theEyeVector.y);
- OUT.btn_z = float4(B.z, T.z, N.z, theEyeVector.z);
-
- half facing = 1.0 - max(dot(theEyeVector, N), 0); // 1 if perpendicular to water surface, 0 if parallel
-
- // fresnel - could use 1D tex lookup for this
- // Fresnel reflectance factor. Water will be more reflective at when looked at long a grazing angle.
- // When looking straight down at water, the surface will reflect very little.
- // Setting fresnelBias to 1.0 means there will be no Fresnel effect. A setting of 0 means
- // the full effect will be used.
- const float kFresnelBias = 0.5f;
- half fresnel = kFresnelBias + (1.0-kFresnelBias)*pow(facing, fresnelPower);
- OUT.color0 = fresnel * reflectionColor * reflectionAmount;
- OUT.color0.a = 0.4; // Alpha value of pixel
-
- // Interpolate between 2 water colors, depending on angle of eye to water surface
- half4 waterColor = lerp(deepColor, shallowColor, facing);
- OUT.color1 = waterColor;
-
- return OUT;
- }
-
-
- // Vertex shader which computes waves, tangent basis to waves, bump map texture coordinates.
- vertexOutput3 VS_Transform3(vertexInput IN,
- uniform float time,
- uniform float waveFreq,
- uniform float waveAmp,
- uniform WAVE theWaves[NWAVES],
- uniform float4x4 theWorldViewProj,
- uniform float4x4 theWorldMatrix,
- uniform float4x4 theView,
- uniform float2 textureScale,
- uniform float2 bumpSpeed,
- uniform float BumpScale,
- uniform float3 theEyePosition,
- uniform float theFogEnd,
- uniform float theFogEndMinusStartInv
- )
- {
- vertexOutput3 OUT;
-
- // We're combining two wave functions. Hard code these values
- // eventually for better performance?
- theWaves[0].freq = waveFreq;
- theWaves[0].amp = waveAmp;
-
- theWaves[1].freq = waveFreq*2.0;
- theWaves[1].amp = waveAmp*0.5;
-
- float3 P = IN.position;
-
- // Now convert world position to camera space.
- // Note that we don't use World Matrix * View Matrix here, 'cause the World Matrix is the identity matrix.
- float4 positionCamSpace = mul( float4(P, 1.0), theView );
-
- // NOTE: P is in camera space
- OUT.fog = clamp(((theFogEnd - positionCamSpace.z) * theFogEndMinusStartInv), 0.0f, 1.0f);
-
- // sum waves
- float ddx = 0.0, ddy = 0.0;
- for(int i=0; i < NWAVES; i++) {
- P.z += evaluateWave(theWaves[i], P.xy, time); //!NOTE changed this to xy from xz, due to Empire Earth code
- float deriv = evaluateWaveDeriv(theWaves[i], P.xy, time);
- // P.z += evaluateWaveSharp(theWaves[i], P.xy, time, 2); //!NOTE changed this to xy from xz
- // float deriv = evaluateWaveDerivSharp(theWaves[i], P.xy, time, 2);
- ddx += deriv * theWaves[i].dir.x;
- ddy += deriv * theWaves[i].dir.y;
- }
-
- // Transform position to clip space
- OUT.Position = mul(float4(P, 1.0), theWorldViewProj);
-
- // compute tangent basis. This is used to convert object space to texture space.
- // N is the normal to the surface, T is the tangent and B is the binormal. T & B
- // follow the texture coordinate axes u and v.
- float3 B = float3(1, ddx, 0);
- float3 T = float3(0, ddy, 1);
- float3 N = float3(-ddx, 1, -ddy);
-
- // pass texture coordinates for fetching the normal map
- OUT.TexCoord.xy = IN.texCoord*textureScale;
-
- // Now we pass in (time in seconds) fmod 200.0, so we don't have to do it for each vertex
- //time = fmod(time, 20.0); // fmod is the floating point remainder
- //OUT.bumpCoord0.xy = IN.texCoord*textureScale + time*bumpSpeed;
- //OUT.bumpCoord1.xy = IN.texCoord*textureScale*2.0 + time*bumpSpeed*4.0;
- //OUT.bumpCoord2.xy = IN.texCoord*textureScale*4.0 + time*bumpSpeed*8.0;
- OUT.bumpCoord0.xy = IN.texCoord*textureScale + timeMod*bumpSpeed;
- OUT.bumpCoord1.xy = IN.texCoord*textureScale*2.0 + timeMod*bumpSpeed*4.0;
- OUT.bumpCoord2.xy = IN.texCoord*textureScale*4.0 + timeMod*bumpSpeed*8.0;
-
- // compute the 3x3 tranform from tangent space to object space
- float3x3 objToTangentSpace;
- // first rows are the tangent and binormal scaled by the bump scale
- objToTangentSpace[0] = BumpScale * normalize(T);
- objToTangentSpace[1] = BumpScale * normalize(B);
- objToTangentSpace[2] = normalize(N);
-
- OUT.TexCoord1.xyz = mul(objToTangentSpace, theWorldMatrix[0].xyz);
- OUT.TexCoord2.xyz = mul(objToTangentSpace, theWorldMatrix[1].xyz);
- OUT.TexCoord3.xyz = mul(objToTangentSpace, theWorldMatrix[2].xyz);
-
- // compute the eye vector (going from shaded point to eye) in cube space
- float3 theEyeVector = theEyePosition - P;
- OUT.eyeVector = theEyeVector.xzy; //swap z & y (in Empire Earth code, Z points up, not Y)
- return OUT;
- }
-
- //-----------------------------------
- // Advanced pixel shader. Uses bump map, environment map, Fresnel reflectance (reflects more
- // at grazing angle, reflects little if looking straight down), high dynamic range (bright areas in
- // env. map are "blown out"), facing (color shifts depending on whether
- // you're looking straight down or at a grazing angle).
- float4 PS_Textured3( vertexOutput3 IN,
- uniform half4 shallowColor,
- uniform half4 deepColor,
- uniform samplerCUBE EnvironmentMap,
- uniform sampler2D NormalMap,
- uniform half4 reflectionColor,
- uniform half4 reflectionAmount,
- uniform half fresnelPower,
- uniform half hdrMultiplier
- ): COLOR
- {
- // sum normal maps
- half4 t0 = tex2D(NormalMap, IN.bumpCoord0.xy)*2.0-1.0;
- half4 t1 = tex2D(NormalMap, IN.bumpCoord1.xy)*2.0-1.0;
- half4 t2 = tex2D(NormalMap, IN.bumpCoord2.xy)*2.0-1.0;
- half3 N = t0.xyz + t1.xyz + t2.xyz;
-
- half3x3 m; // tangent to world matrix
- m[0] = IN.TexCoord1;
- m[1] = IN.TexCoord2;
- m[2] = IN.TexCoord3;
- half3 Nw = mul(m, N.xyz);
- Nw = normalize(Nw); // normal to water surface, taking bump map & waves into account
-
- // Get reflection vector & look up value in environment map.
- float3 E = normalize(IN.eyeVector);
- half3 R = reflect(-E, Nw);
- half4 reflection = texCUBE(EnvironmentMap, R);
-
- // hdr effect (multiplier in alpha channel)
- reflection.rgb *= (1.0 + reflection.a*hdrMultiplier);
-
- // fresnel - could use 1D tex lookup for this
- // Fresnel reflectance factor. Water will be more reflective at when looked at long a grazing angle.
- // When looking straight down at water, the surface will reflect very little.
- // Setting fresnelBias to 1.0 means there will be no Fresnel effect. A setting of 0 means
- // the full effect will be used.
- const float kFresnelBias = 0.1f;
- half facing = 1.0 - max(dot(E, Nw), 0); // 1 if perpendicular to water surface, 0 if parallel
- half fresnel = kFresnelBias + (1.0-kFresnelBias)*pow(facing, fresnelPower);
-
- // Interpolate between 2 water colors, depending on angle of eye to water surface
- half4 waterColor = lerp(deepColor, shallowColor, facing);
-
- float4 color;
- color = waterColor + reflection*reflectionColor*reflectionAmount*fresnel;
- // color = waterColor;
- // color = fresnel;
- // color = reflection;
-
- color.a = 0.4; // Alpha value of pixel
- return color;
- }
-
- // A technique is the effect we're trying to achieve.
- //-----------------------------------
-
- // Intermediate vertex & pixel shader. Environment map & bump mapping.
- technique RenderWaterMid
- {
- pass p0
- {
- VertexShader = compile vs_1_1 VS_Transform2(time,waveFreq, waveAmp, wave, worldViewProj,
- view, textureScale, bumpSpeed, bumpHeight,
- eyePositionW, fogEnd, fogEndMinusStartInv);
- ZEnable = true; // was true
- ZWriteEnable = true; // was true
- CullMode = CCW; // was None; We won't see the river if we go under water (happens if cammera follows a rocking boat)
- PixelShader =
- asm
- {
- ps_1_1
-
- tex t0
- texm3x3pad t1, t0_bx2
- texm3x3pad t2, t0_bx2
- texm3x3vspec t3, t0_bx2
-
- mad r0.rgb, t3, v0, v1;
- +mov r0.a, v0;
- };
- Sampler[0] = (normalMapSampler);
- Sampler[1] = (normalMapSampler);
- Sampler[2] = (normalMapSampler);
- Sampler[3] = (envMapSampler);
- }
- }
-
- // Whole tamale. Environment map, bump map, Fresnel reflectance factor, High Dynamic Range, water changes color
- // depending on eye vector & water's nomal.
- technique RenderWater
- {
- pass p0
- {
- VertexShader = compile vs_2_0 VS_Transform3(time,waveFreq, waveAmp, wave,
- worldViewProj, worldMatrix, view,
- textureScale, bumpSpeed, bumpHeight,
- eyePositionW, fogEnd, fogEndMinusStartInv );
- ZEnable = true;
- ZWriteEnable = true;
- CullMode = CCW; // was None; We won't see the river if we go under water (happens if cammera follows a rocking boat)
- PixelShader = compile ps_2_0 PS_Textured3(shallowColor, deepColor, envMapSampler,
- normalMapSampler,
- reflectionColor, reflectionAmount,
- fresnelPower, hdrMultiplier);
- }
- }